﻿/**********************************************************/
/*                Code by: Sam Wronski                    */
/*             email: runewake2@gmail.com                 */
/* Distributed under the Microsoft Public License (Ms-PL) */
/**********************************************************/
/*     https://gamejolttrophies.codeplex.com/license      */
/**********************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.ComponentModel;

namespace GameJoltAPI
{
    public enum SessionStatus
    {
        Active,
        Idle
    }

    /// <summary>
    /// Handles a Games Session
    /// </summary>
    public class SessionClient
    {
        private static readonly string _url_open = @"http://gamejolt.com/api/game/v1/sessions/open/?format=dump";
        private static readonly string _url_ping = @"http://gamejolt.com/api/game/v1/sessions/ping/?format=dump";
        private static readonly string _url_close = @"http://gamejolt.com/api/game/v1/sessions/close/?format=dump";

        Timer timer;
        SessionStatus _status;
        bool auto; //if the session should automatically ping
        bool pingOnSessionChange;
        bool closed;
        private static readonly float defaultinterval = 5000;
        float interval;

        public SessionStatus Status
        {
            get { return _status; }
            set
            {
                if (_status != value)
                {
                    _status = value;
                    if (pingOnSessionChange)
                        Ping();
                }
            }
        }

        public bool AutomaticallyPing { get { return auto; } set { auto = value; } }
        public bool PingOnStatusChange { get { return pingOnSessionChange; } set { pingOnSessionChange = value; } }

        public float Interval
        {
            get { return interval; }
            set
            {
                if (interval != value)
                {
                    interval = value;
                    timer.Interval = interval;
                }
            }
        }

        /// <summary>
        /// Creates a new session, which, by default will be marked as Active,
        /// will automatically Ping every 30 seconds, and will not ping when
        /// the Status is changed.
        /// </summary>
        public SessionClient()
        {
            _status = SessionStatus.Active;
            pingOnSessionChange = false;
            closed = false;
            auto = true;

            interval = defaultinterval;
            timer = new Timer(interval);
            timer.Elapsed += (sender,arg) =>
                {
                    if (auto)
                        Ping();
                };
            timer.Start();

            Open();
        }

        /// <summary>
        /// Sets a new Status for the Session and, if PingOnStatusChange is true, pings the server.
        /// </summary>
        /// <param name="ns">The new Status</param>
        /// <returns>The old Status</returns>
        public SessionStatus NewStatus(SessionStatus ns)
        {
            if (ns != _status)
            {
                SessionStatus old = Status;
                Status = ns;
                return old;
            }
            return _status;
        }

        /// <summary>
        /// Opens a new Session
        /// </summary>
        private void Open()
        {
            closed = false;
            string url = _url_open;

            url += "&game_id=" + Settings.GameID;
            url += "&username=" + Settings.Username;
            url += "&user_token=" + Settings.Token;

            BeginResult(url);
        }

        /// <summary>
        /// Closes a Session, you will need to create a new Session to Open it again
        /// </summary>
        public void Close()
        {
            closed = true;
            timer.Stop();

            string url = _url_close;

            url += "&game_id=" + Settings.GameID;
            url += "&username=" + Settings.Username;
            url += "&user_token=" + Settings.Token;

            BeginResult(url);
        }

        /// <summary>
        /// Pings the server with the Sessions current State.
        /// This keeps the Session Active.</para>
        /// </summary>
        public void Ping()
        {
            //Don't ping if session is closed
            if (closed)
                return;

            string url = _url_ping;

            url += "&game_id=" + Settings.GameID;
            url += "&username=" + Settings.Username;
            url += "&user_token=" + Settings.Token;
            url += "&status=" + (_status == SessionStatus.Active ? "active" : "idle");

            BeginResult(url);
        }

        //This gets the result
        private void BeginResult(string url)
        {
            string rs = url + "&signature=" + Settings.Signiture(url); //Append signiture

            NetworkAccess.StartConnection();

            //TODO: Web API Call
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(rs);
            request.Method = "GET";
            request.BeginGetResponse(EndFetchResult, request);
        }

        //This fetches the result data
        private void EndFetchResult(IAsyncResult result)
        {
            NetworkAccess.FinishConnection();

            if (result.IsCompleted)
            {
                HttpWebRequest request = (HttpWebRequest)result.AsyncState;

                //Deserialize the data and call the event
                //string data = new StreamReader(request.EndGetResponse(result).GetResponseStream()).ReadToEnd();
                //if (data.ToLower()[0] == 'f')
                    //throw new Exception(data);

            }
        }
    }
}
